package hermesV3.services.TupleSpace;

import it.unicam.cs.cosy.bioshape.core.components.GlobalCoordinator;
import it.unicam.cs.cosy.bioshape.core.util.Messages;

import java.io.Serializable;
import java.util.Set;

import org.sercho.masp.space.TupleSpace;

import hermesV3.Message;
import hermesV3.agent.CommunicationException;
import hermesV3.agent.Identifier;
import hermesV3.agent.InteractionContainer;
import hermesV3.agent.UserAgent;
import hermesV3.protocols.SynProtocol;
import hermesV3.protocols.TupleSpaceProtocol;
import hermesV3.services.HubAgent;

/**
 * 
 * @author Ambruoso Luigi
 * @author Addeo Vincenzo
 * 
 */
public class TupleSpaceManager extends UserAgent implements Serializable {
	/**
	 * 
	 */
	private static final long serialVersionUID = -2042364095172559728L;
	// Protocols
	private SynProtocol synProtocol = new SynProtocol();
	private TupleSpaceProtocol tsProtocol = new TupleSpaceProtocol();

	private Identifier generalId;

	private TupleSpace<Tuple> space;

	/**
	 * Key used in the parameters HashMap which icon corresponds to the tuple to
	 * insert or search, used in read, readAll, remove, removeAll, write
	 */
	public static String TUPLA = "Tupla";
	/**
	 * Key used in the parameters HashMap which icon corresponds to the set of
	 * tuple to write, used in writeAll
	 */
	public static String TUPLESET = "TupleSet";
	/**
	 * Response of a write or writeAll
	 */
	public static String WRITERESP = "OK";

	public TupleSpaceManager(String UserAgentName) {
		super(UserAgentName);
		space = Space.getInstance();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see hermesV3.agent.Agent#init()
	 */
	@Override
	public void init() {
		reception();

		Message<?> msgFromHub = getMessageSynch(HubAgent.class
				.getSimpleName());
		// spacchetto il messaggio
		InteractionContainer ic = (InteractionContainer) msgFromHub.getObject();

		if (!ic.validate(synProtocol)) {
			System.out.println("TupleSpace:protocol error! (from Hub)");
		} else {
			System.out
					.println("TupleSpace:I received a message from the HubServiceAgent");
			generalId = (Identifier) ic.getParameter("Syn");

		}
		ic.makeInteraction("SynAck", this.getIdentifier());
		Message<InteractionContainer> msgToGeneral = new Message<InteractionContainer>(
				this.getIdentifier(), generalId, ic);
		try {
			this.sendMessageToUserAgent(msgToGeneral);
		} catch (CommunicationException e) {

			System.out.println("TupleSpace: error send message to General");
		}

		Message<?> msgFromGeneral = Messages.receiveAck(this,
				GlobalCoordinator.class);

		if (msgFromGeneral == null)
			System.out.println("TupleSpace:protocol error! (from General)");
		//
		// array che conterra la risposta uso un array anche se non necessario
		// perche il metodo si aspetta un array
		Set<Tuple>[] arrayResp = new Set[1];

		while (true) {
			arrayResp[0] = null;
			Message<?> msg = getMessageSynch();
			// TODO switch
			InteractionContainer ic2 = (InteractionContainer) msg.getObject();
			if (ic2.validate(tsProtocol)) {
				// TODO la key per la tupla deve essere TupleSpaceManager.TUPLA
				if (TupleSpaceProtocol.INTERACTIONREADALL.equals(ic2
						.getInteractionName())) {
					arrayResp[0] = space.readAll((Tuple) ic2
							.getParameter(TUPLA));
					ic2.makeResponseInteraction(arrayResp);
					continue;
				}
				if (TupleSpaceProtocol.INTERACTIONREMOVEALL.equals(ic2
						.getInteractionName())) {
					arrayResp[0] = space.removeAll((Tuple) ic2
							.getParameter(TUPLA));
					ic2.makeResponseInteraction(arrayResp);
					continue;
				}
				if (TupleSpaceProtocol.INTERACTIONREAD.equals(ic2
						.getInteractionName())) {
					arrayResp[0]
							.add(space.read((Tuple) ic2.getParameter(TUPLA)));
					ic2.makeResponseInteraction(arrayResp);
					continue;
				}
				if (TupleSpaceProtocol.INTERACTIONREMOVE.equals(ic2
						.getInteractionName())) {
					arrayResp[0].add(space.remove((Tuple) ic2
							.getParameter(TUPLA)));
					ic2.makeResponseInteraction(arrayResp);
					continue;
				}
				if (TupleSpaceProtocol.INTERACTIONWRITE.equals(ic2
						.getInteractionName())) {
					space.write((Tuple) ic2.getParameter(TUPLA));
					String arrayRespString[] = { "WRITERESP" };
					ic2.makeResponseInteraction(arrayRespString);
					continue;
				}
				// TODO la space non prevede WriteAll, noi si, in modo da
				// evitare
				// miriadi di messaggi. Basta inserire
				// un set di Tuple nell'InteractionContainer e come chiave usare
				// TupleSpaceManager.TUPLESET
				if (TupleSpaceProtocol.INTERACTIONWRITEALL.equals(ic2
						.getInteractionName())) {
					Set<Tuple> set = (Set<Tuple>) ic2.getParameter(TUPLESET);
					for (Tuple t : set) {
						space.write(t);
					}
					String arrayRespString[] = { "WRITERESP" };
					ic2.makeResponseInteraction(arrayRespString);
					continue;
				}
			}
			// ERROR BLOCK
			ic2.makeInteraction("Error", "Illegal Message");
			msg = new Message<InteractionContainer>(this.getIdentifier(),
					msg.getSenderAgentId(), ic2);
			try {
				this.sendMessageToUserAgent(msg);
			} catch (CommunicationException e) {
				System.out.println("TupleSpace: Illegal Message");
			}
		}
	}
}
